home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
501-525
/
disk_503
/
pcq
/
pcq12asc.lzh
/
Runtime
/
PCQ
/
Openers.asm
< prev
next >
Wrap
Assembly Source File
|
1991-04-12
|
9KB
|
323 lines
* Openers.asm (of PCQ Pascal runtime library)
* Copyright (c) 1989 Patrick Quaid
* This file takes care of opening and closing DOS files. In
* much the same way as the memory routines, these routines keep a
* list of the open files around. Open() puts the files on the list
* and Close() takes them off.
SECTION PCQ_Runtime,CODE
XREF _p%DOSBase
XREF _LVOOpen
XREF _LVOIsInteractive
XREF _LVOIoErr
XREF _p%new
XREF _p%dispose
XREF _p%ExitWithAddr
XREF _LVORead
XREF _LVOClose
XREF _p%IOResult
XREF _p%FlushBuffer
XREF i_lmul
XREF i_ldiv
XDEF filekey
* OpenB is the routine called by the open() and reopen() calls.
* It calls, in turn, Open, then returns true or false depending
* on whether there was an error. It always clears IOResult.
* algorithm for open:
*
* HANDLE := DOSOpen handle
* if then handle = nil
* set IOResult := IoErr
* return
* INTERACTIVE := IsInteractive
* if INTERACTIVE and (Access = ModeOldFile) then
* MAX := RECSIZE
* else
* MAX := (MAX div RECSIZE) * RECSIZE
* if MAX = 0 then
* MAX := RECSIZE
* Allocate BUFFER of size MAX
* if BUFFER = nil then
* close HANDLE
* set IOResult to 50
* return
* set MAX := BUFFER (First position) + MAX (buffer size)
* - thus MAX points to first byte AFTER buffer
* CURRENT := BUFFER
* LAST := BUFFER
* EOF := False
* if (Access = ModeOldFile) and (not INTERACTIVE) then
* FillBuffer
* link into file list
* return
* Upon entry, the stack looks like:
*
* 4(SP) -> Address of File Record
* 8(SP) -> Address of File Name String
*
* The File Record is initialized with the following values:
*
* ACCESS = either ModeOldFile or ModeNewFile
* RECSIZE = the size of a record (1 for Text files)
* MAX = the buffer size requested
*
INCLUDE "/FileRec.i"
XDEF _p%Open
_p%Open
move.l 4(sp),d0
move.l 8(sp),d1
move.l d1,-(sp)
move.l d0,-(sp)
bsr _p%OpenB
tst.l _p%IOResult
seq d0
clr.l _p%IOResult
add.w #8,sp
rts
XDEF _p%OpenB
_p%OpenB
move.l 8(sp),d1 ; get file name
move.l 4(sp),a0 ; get address of FileRec
moveq.l #0,d2 ; clear out upper word
move.w ACCESS(a0),d2 ; get access mode
move.l _p%DOSBase,a6
jsr _LVOOpen(a6) ; open the file
move.l 4(sp),a0
move.l d0,HANDLE(a0) ; save the file handle
bne.s OpenedOK ; no errors
jsr _LVOIoErr(a6) ; get the error number
move.l d0,_p%IOResult ; set IOResult
rts ; return
OpenedOK
move.l d0,d1 ; set up caller
jsr _LVOIsInteractive(a6) ; is it interactive ?
move.l 4(sp),a0 ; get file rec
move.b d0,INTERACTIVE(a0) ; set interactive
beq.s AdjustBuffer ; if not interactive, skip this
cmp.w #1005,ACCESS(a0) ; is it an input file ?
bne.s AdjustBuffer ; if not, skip
move.l RECSIZE(a0),d0 ; d0 := RECSIZE
move.l d0,MAX(a0) ; save size for later
bra.s AllocBuffer ; go to allocate the buffer
AdjustBuffer
move.l MAX(a0),d0 ; d0 := Buffer Size requested
move.l RECSIZE(a0),d1 ; d1 := record size
jsr i_ldiv ; call 32-bit divide routines. d0/d1 in d0
tst.l d0 ; is it zero?
bne.s 1$ ; if not, skip
moveq.l #1,d0 ; at least 1
1$ move.l 4(sp),a0 ; get file rec
move.l RECSIZE(a0),d1 ; d1 := record size again
jsr i_lmul ; d0 := (max div recsize) * recsize
move.l 4(sp),a0 ; get file rec address
move.l d0,MAX(a0) ; save it for later
AllocBuffer
jsr _p%new ; allocate buffer
move.l 4(sp),a0 ; a0 := file record address
move.l d0,BUFFER(a0) ; set buffer
bne.s InitializeFR ; if OK, initialize record
move.l HANDLE(a0),d1 ; set up for close
move.l _p%DOSBase,a6 ; get DOS library base
jsr _LVOClose(a6) ; close the file
move.l #50,_p%IOResult ; Set IO Result = no memory for buffer
rts ; return, having failed
InitializeFR
move.l MAX(a0),a1 ; get buffer size
adda.l BUFFER(a0),a1 ; add to first address
move.l a1,MAX(a0) ; set maximum address: last byte + 1
move.l BUFFER(a0),a1 ; a1 := first byte
move.l a1,CURRENT(a0) ; CURRENT := BUFFER
move.l a1,LAST(a0) ; LAST := BUFFER
move.b #0,EOF(a0) ; EOF := False
cmp.w #1005,ACCESS(a0) ; is input file ?
bne.s LinkFile ; if not, skip this
tst.b INTERACTIVE(a0) ; is it interactive ?
bne.s LinkFile ; if so, skip this
jsr _p%FillBuffer ; fill the buffer for input file
LinkFile
move.l filekey,NEXT(a0) ; a0.Next := filekey
move.l a0,filekey ; filekey := a0 (linked a0 into list)
rts ; return successful
XDEF _p%FillBuffer
_p%FillBuffer
* Read as many bytes as possible into the file's buffer
* on entry, a0 is the address of the file record, which contains
* all the important info. This routine sets EOF
* Algorithm:
*
* if IOResult <> 0 then
* return
* if EOF then
* set IOResult and return
* Read MAX - BUFFER bytes into BUFFER
* CURRENT := BUFFER
* LAST := BUFFER + bytes read
* if LAST = BUFFER then
* EOF := True
*
tst.l _p%IOResult ; is IO OK?
bne 3$ ; if not, leave now
tst.b EOF(a0) ; at EOF?
beq.s 1$ ; if not, skip ahead
move.l #51,_p%IOResult ; set IOResult = Access past EOF
rts
1$ move.l a0,-(sp) ; save the File Rec
move.l HANDLE(a0),d1 ; get the file handle
bne.s 2$ ; if it's open, skip
jsr _p%MayOpenInput ; if not, try to open input
move.l HANDLE(a0),d1 ; if we got here, we must be OK
2$ move.l BUFFER(a0),d2 ; get first address
move.l d3,-(sp) ; save d3
move.l MAX(a0),d3 ; get last address + 1
sub.l d2,d3 ; number of bytes to read
move.l _p%DOSBase,a6 ; get dos.library
jsr _LVORead(a6)
move.l (sp)+,d3 ; restore d3
move.l (sp)+,a0 ; get file record back
move.l BUFFER(a0),d1 ; get initial position
move.l d1,CURRENT(a0) ; set CURRENT := initial
add.l d0,d1 ; get BUFFER + bytes read
move.l d1,LAST(a0) ; LAST := BUFFER + bytes read
tst.l d0 ; did we actually read anything?
bne.s 3$ ; if so, skip
move.b #-1,EOF(a0) ; set EOF := True
3$ rts
* MayOpenInput
*
* This routine opens a Standard Input window for programs that
* may have started from the Workbench. It gets the window spec
* from _StdInName, which is defined either in the User program
* or, by default, in this library. If the Output file is already
* open, and it's interactive, that already open file is used.
*
* Algorithm for MayOpenInput:
*
* if a0 <> Input then
* generate a runtime error
* if Output is open and interactive then
* Output.Handle := Input.Handle
* else
* Open(StdInName, Input)
* if it did not open OK
* generate a runtime error
*
* Upon entry to this routine, a0 holds the address of the
* File Record, which may or may not be Input.
XREF _p%exit
XREF _StdInName
XREF _Input
XREF _Output
_p%MayOpenInput
cmpa.l #_Input,a0 ; is it Input?
beq.s 1$ ; if so, skip this
move.l #52,d0 ; runtime error
jsr _p%ExitWithAddr ; generate the error
1$ move.l #_Output,a1 ; get Input ptr
tst.l HANDLE(a1) ; is it open?
beq 2$ ; if not, open a new one
tst.b INTERACTIVE(a1) ; is it interactive?
bne 2$ ; if not, open a new file
move.l HANDLE(a1),a1 ; get the file handle
move.l a1,HANDLE(a0) ; and copy it over
rts ; and try that one
2$ move.l #80,MAX(a0) ; set up for Open call
move.l #1,RECSIZE(a0) ; Text file
move.w #1005,ACCESS(a0) ; it's an input file (ModeOldFile)
move.l _StdInName,-(sp) ; push the file name
move.l a0,-(sp) ; push the file record address
jsr _p%Open ; try to open this file
move.l (sp)+,a0 ; retrieve file record
addq.l #4,sp ; and fix stack
tst.b d0 ; did it go OK?
bne.s 3$ ; if so, go on
move.l #53,d0 ; if not, generate an error
jsr _p%ExitWithAddr ; goodbye
3$ rts ; return to sender
* Close the file
*
* This routine unlinks the file from the open-file list, then
* de-allocates the buffer and closes the file. If the file
* is for some reason not on the open-file list, the routine
* attempts to close it and deallocate its buffer anyway. Thus
* you can generate several types of errors by closing a file
* twice.
*
* Algorithm:
*
* if filekey <> nil then
* if filekey = FileRec then
* filekey := FileRec.NEXT
* else
* a1 := filekey
* while a1 <> nil do
* if a1.Next = FileRec then
* a1.Next := FileRec.Next
* skip ahead to FlushBuffer business
* a1 := a1.Next
* if ACCESS = ModeNewFile then
* FlushBuffer
* DOSClose(HANDLE)
* Dispose(BUFFER)
*
* Upon entry, a0 holds the address of the file record
*
XDEF _p%Close
_p%Close:
move.l filekey,a1 ; a1 := filekey
move.l a1,d0 ; to set flags
beq 3$ ; if Nil, skip all this
cmpa.l a1,a0 ; is a0 = filekey?
bne.s 1$ ; if not, go to loop
move.l NEXT(a1),a1 ; unlink the first file
move.l a1,filekey ; set filekey := filekey.Next
bra 3$ ; go to flush buffer stuff
1$ cmpa.l NEXT(a1),a0 ; a0 = NEXT(a1)
bne.s 2$ ; if not, skip this
move.l a2,-(sp) ; save a2 for now
move.l NEXT(a0),a2 ; a2 := file after a0
move.l a2,NEXT(a1) ; a1.Next := a0.Next (lose a0)
move.l (sp)+,a2 ; retrieve a2
bra.s 3$ ; and do the rest of close
2$ move.l NEXT(a1),a1 ; advance file record ptr
move.l a1,d0 ; are we at end of list?
bne.s 1$ ; if not, go on
3$ move.l a0,-(sp) ; save file record
cmp.w #1006,ACCESS(a0) ; was it ModeNewFile ?
bne.s 4$ ; if not, skip
jsr _p%FlushBuffer ; otherwise flush the buffer
4$ move.l HANDLE(a0),d1 ; get handle
move.l _p%DOSBase,a6 ; get DOS address
jsr _LVOClose(a6) ; close the file
move.l (sp)+,a0 ; get file record back
move.l BUFFER(a0),d0 ; get initial address
jsr _p%dispose ; de-allocate it
rts
SECTION FileKey
filekey dc.l 0
END